package com.meme.io.editor;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;

import com.meme.editor.level.*;
import com.meme.editor.level.define.ActorTemplate;
import com.meme.editor.level.define.AppearanceDefine;
import com.meme.editor.level.define.DefineFile;
import com.meme.editor.level.define.Parameter;
import com.meme.editor.level.define.PropertyDefine;
import com.meme.editor.level.define.PropertyDefineBlock;
import com.meme.util.XmlUtil;

import java.util.List;
import java.util.Vector;

public class DefineXmlFileLoader {

	static Logger logger = Logger.getLogger(DefineXmlFileLoader.class);
	
	
	String mDefineFilename;

	public DefineFile loadFromXmlDocument(Document document, String filename) 
	{
		mDefineFilename = filename;
		
		DefineFile defineFile = new DefineFile();

		loadDefineFile(document, defineFile);
		
		defineFile.setHostFilename(filename);

		evalEntityRefs(defineFile);

		return defineFile;
	}

	
//================================================================================
// 
//================================================================================
	
	void loadDefineFile (Document document, DefineFile defineFile)
	{
		Element defineElement = XmlUtil.getChildElementByName (document, "Define");
		
		String version = defineElement.getAttribute("version");		
		logger.assertLog(version.equals("1.0"), "version is not 1.0.");
		
		// parameters
		{
			List<Parameter> paramList = readParameterListFromElement (defineElement);
			defineFile.addParameters (paramList);
		}
		
		// item lists
		{
			Element[] listElements = XmlUtil.getChildElementsByName (defineElement, "ItemList");
			
			for (Element listElement : listElements)
			{
				String listName  = listElement.getAttribute ("name");
				List<Parameter> paramList = readParameterListFromElement (listElement);
				
				defineFile.addItemList (listName, paramList);
			}
		}
		
		// property define blocks
		{
			List<PropertyDefineBlock> propetyDefBlcokList = readPropetyDefBlcokListFromElement (defineElement, null);
			defineFile.addPropertyDefBlcks (propetyDefBlcokList); 
		}
		
		// actor templates
		{
			Element[] templateElements = XmlUtil.getChildElementsByName (defineElement, "ActorTemplate");
			
			for (Element templateElement : templateElements)
			{
				String templateName = templateElement.getAttribute ("name");				
				String actorType = templateElement.getAttribute ("type");			
				int zOrder = XmlUtil.parseAttributeAsInt (templateElement, "z-order");
				
				Element appearanceElement = XmlUtil.getChildElementByName (templateElement, "InstanceAppearanceDefines");
				List<AppearanceDefine> appearanceDefineList = readAppearanceDefineListFromElement (appearanceElement);
				
				Element instancePropertiesElement = XmlUtil.getChildElementByName (templateElement, "InstancePropertyDefines");
				List<PropertyDefineBlock> instancePropetyDefGroupList = readPropetyDefBlcokListFromElement (instancePropertiesElement, defineFile);
				
				Element templatePropertiesElement = XmlUtil.getChildElementByName (templateElement, "TemplatePropertyDefines");
				List<PropertyDefineBlock> templatePropetyDefGroupList = readPropetyDefBlcokListFromElement (templatePropertiesElement, defineFile);
				

				ActorTemplate actorTemplate = new ActorTemplate (templateName, actorType, zOrder);
				//defineFile.addActorTemplate (templateName, actorTemplate);
				defineFile.addActorTemplate (actorTemplate);

				actorTemplate.addAppearanceDefines (appearanceDefineList);
				actorTemplate.addInstancePropertyDefines (instancePropetyDefGroupList);
				actorTemplate.addTemplatePropertyDefines (templatePropetyDefGroupList);
			}
		}
	}
	
	List<Parameter> readParameterListFromElement (Element element)
	{
		List<Parameter> paramList = new Vector<Parameter> ();
		
		Element[] paramElements = XmlUtil.getChildElementsByName (element, "Parameter");
		
		for (Element paramElement : paramElements)
		{
			String paramName  = paramElement.getAttribute ("name");
			String paramValue = paramElement.getAttribute ("value");
			
			paramList.add (new Parameter (paramName, paramValue));
		}
		
		return paramList;
	}
	
	List<PropertyDefine> readPropertyDefineListFromElement (Element element, DefineFile defineFile)
	{
		List<PropertyDefine> defList = new Vector<PropertyDefine> ();
		
		Node node = element.getFirstChild();
		while (node != null)
		{
			if (node instanceof Element )
			{
				Element defElement = (Element) node;
				String tagName = defElement.getTagName ();
				if (tagName.equals("PropertyDef"))
				{
					String name         = defElement.getAttribute ("name");
					String valueType    = defElement.getAttribute ("value-type");
					String defaultValue = defElement.getAttribute ("default-value");
					String controlType  = defElement.getAttribute ("control_type");
					String editable  = defElement.getAttribute ("editable");
					
					List<Parameter> paramList = readParameterListFromElement (defElement);

					PropertyDefine def = new PropertyDefine (
							name, valueType, defaultValue, 
							controlType.length() == 0 ? null : controlType, 
							editable.length() == 0 ? true : Boolean.parseBoolean (editable) );
					def.addParamters (paramList);
					
					defList.add (def);
				}
				else if (defineFile != null && tagName.equals("PropertyDefBlockImport"))
				{
					String blockName = defElement.getAttribute ("block-name");
					PropertyDefineBlock defineBlock = defineFile.getPropertyDefBlock (blockName);
					if (defineBlock != null)
					{
						defList.addAll (defineBlock.clonePropertyDefines());
						
						Element[] modifyElements = XmlUtil.getChildElementsByName (defElement, "PropertyDefaultValueModify");
						for (Element modifyElement : modifyElements)
						{
							String modifiedPropertyName = modifyElement.getAttribute ("name");
							String newDefaultVaule = modifyElement.getAttribute ("value");
							
							for (PropertyDefine propertyDefine : defList)
							{
								if (propertyDefine.getName().equals (modifiedPropertyName))
								{
									propertyDefine.setDefaultValue (newDefaultVaule);
									break;
								}
							}
						}
					}
				}
			}
			
			node = node.getNextSibling();
		}
		
		return defList;
	}
	
	List<PropertyDefineBlock> readPropetyDefBlcokListFromElement (Element element, DefineFile defineFile)
	{
		List<PropertyDefineBlock> defBlockList = new Vector<PropertyDefineBlock> ();
		
		Element[] blockElements = XmlUtil.getChildElementsByName (element, defineFile != null ? "PropertyGroup" : "PropetyDefBlcok");
		
		for (Element blockElement : blockElements)
		{
			String blockName = blockElement.getAttribute ("name");				
			List<PropertyDefine> propertyDefineList = readPropertyDefineListFromElement (blockElement, defineFile);

			PropertyDefineBlock propertyDefBlock = new PropertyDefineBlock (blockName);
			propertyDefBlock.addPropertyDefines (propertyDefineList);
			
			defBlockList.add (propertyDefBlock);
		}
		
		return defBlockList;
	}
		
	
	List<AppearanceDefine> readAppearanceDefineListFromElement (Element element)
	{
		List<AppearanceDefine> defList = new Vector<AppearanceDefine> ();
		
		Element[] defElements = XmlUtil.getChildElementsByName (element, "AppearanceDef");
		
		for (Element defElement : defElements)
		{
			String name         = defElement.getAttribute ("name");
			String type    = defElement.getAttribute ("type");
			
			List<Parameter> paramList = readParameterListFromElement (defElement);
			
			AppearanceDefine def = new AppearanceDefine (name, type);
			def.addParamters (paramList);
			
			defList.add (def);
		}
		
		return defList;
	}
	

	void evalEntityRefs (DefineFile defineFile)
	{
		
	}
}
